﻿/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Foundation Framework
 * Version 2.10
 * 
 * CNR Authentication Session Class
 *      Provides a basic definition for implementing authentication portions of 
 * command-and-response protocols.
 *------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------
 * System Imports
 *------------------------------------------------------------------------------*/
using System;
using Adaptive.Foundation;

namespace Adaptive.Foundation.Network.Cnr
{
    /// <summary>
    /// Provides a basic definition for implementing authentication portions of 
    /// command-and-response protocols.
    /// </summary>
    public abstract class CnrAuthenticationSession : CnrObjectBase
    {
        /*--------------------------------------------------------------------------------
         * Public Event Definitions
         *------------------------------------------------------------------------------*/
        #region Public Event Definitions
        /// <summary>
        /// Occurs when the user identity value is sent.
        /// </summary>
        public event CnrAuthenticationEventHandler UserIdentitySent;
        /// <summary>
        /// Occurs when the user identity value is accepted.
        /// </summary>
        public event CnrAuthenticationEventHandler UserIdentityAccepted;
        /// <summary>
        /// Occurs when the user identity value is rejected.
        /// </summary>
        public event CnrAuthenticationEventHandler UserIdentityRejected;
        /// <summary>
        /// Occurs when the security / password value is sent.
        /// </summary>
        public event CnrAuthenticationEventHandler UserPasswordSent;
        /// <summary>
        /// Occurs when the security / password value is accepted.
        /// </summary>
        public event CnrAuthenticationEventHandler UserPasswordAccepted;
        /// <summary>
        /// Occurs when the security / password value is rejected.
        /// </summary>
        public event CnrAuthenticationEventHandler UserPasswordRejected;
        /// <summary>
        /// Occurs when new credential data is required.
        /// </summary>
        public event CnrAuthenticationRequiredEventHandler QueryCredentials;
        #endregion

        /*--------------------------------------------------------------------------------
         * Private Member Declarations
         *------------------------------------------------------------------------------*/
        #region Private Member Declarations

        private CnrCredentials _credentials;
        private bool _isLocal;
        private bool _queryForCredentials;
        private int _retryAttempts;

        #endregion

        /*--------------------------------------------------------------------------------
         * Constructor / Dispose / Destructor Methods
         *------------------------------------------------------------------------------*/
        #region Constructor / Dispose / Destructor Methods
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <remarks>
        /// This is the default constructor.
        /// </remarks>
        public CnrAuthenticationSession()
            : base()
        {
            _credentials = new CnrCredentials();
            _isLocal = true;
            _queryForCredentials = true;
            _retryAttempts = 3;
        }
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <param name="credentials">
        /// A <see cref="CnrCredentials"/> instance containing the credentials data to use.
        /// </param>
        public CnrAuthenticationSession(CnrCredentials credentials)
            : base()
        {
            _credentials = credentials;
            _isLocal = false;
            _queryForCredentials = true;
            _retryAttempts = 3;
        }
        /// <summary>
        /// Deallocates internally allocated objects.
        /// </summary>
        /// <param name="disposing">
        /// A value indicating whether the object is being disposed.
        /// </param>
        protected override void Dispose(bool disposing)
        {
            if ((!Disposed) && (disposing))
            {
                if ((_isLocal) && (_credentials != null))
                    _credentials.Dispose();
            }

            _credentials = null;
            base.Dispose(disposing);
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Properties
         *------------------------------------------------------------------------------*/
        #region Public Properties
        /// <summary>
        /// Gets the reference to the credentials used in the authentication process.
        /// </summary>
        /// <value>
        /// A <see cref="CnrCredentials"/> instance.
        /// </value>
        public CnrCredentials Credentials
        {
            get { return _credentials; }
        }
        /// <summary>
        /// Gets or sets a value indicating whether to query for new credentials on failure.
        /// </summary>
        /// <value>
        /// <b>true</b> to query for credentials before a retry attempt; otherwise, <b>false</b>.
        /// </value>
        public bool QueryForCredentials
        {
            get { return _queryForCredentials; }
            set { _queryForCredentials = value; }
        }
        /// <summary>
        /// Gets or sets the number of retry attempts before failing the authentication process.
        /// </summary>
        /// <value>
        /// The number of times to retry authentication before giving up.
        /// </value>
        public int RetryAttempts
        {
            get { return _retryAttempts; }
            set { _retryAttempts = value; }
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Protected Methods 
         *------------------------------------------------------------------------------*/
        #region Protected Methods 
        /// <summary>
        /// Performs the user identifcation portion of the authentication process.
        /// </summary>
        /// <remarks>
        /// This must be overridden for each implemented protocol.
        /// </remarks>
        /// <returns>
        /// <b>true</b> if the operation is successful; otherwise, <b>false</b>.
        /// </returns>
        protected abstract bool PerformUserIdentification();
        /// <summary>
        /// Performs the security/password validation portion of the authentication process.
        /// </summary>
        /// <remarks>
        /// This must be overridden for each implemented protocol.
        /// </remarks>
        /// <returns>
        /// <b>true</b> if the operation is successful; otherwise, <b>false</b>.
        /// </returns>
        protected abstract bool PerformSecurityValidation();
        /// <summary>
        /// Optionally performs a customized portion of the authentication process.
        /// </summary>
        /// <remarks>
        /// This method may be overidden to implement any custom processes for the authentication
        /// process.
        /// </remarks>
        /// <returns>
        /// <b>true</b> if the operation is successful; otherwise, <b>false</b>.
        /// </returns>
        protected virtual bool PerformCustomOperation()
        {
            return true;
        }
        /// <summary>
        /// Attempts the authenticate the user identity.
        /// </summary>
        /// <remarks>
        /// This method may attempt to re-try on failure, and query for credentials if the flag is set.
        /// 
        /// The method calls the <see cref="PerformUserIdentification"/> implementation.
        /// </remarks>
        /// <returns>
        /// <b>true</b> if the operation is successful; otherwise, <b>false</b>.
        /// </returns>
        protected virtual bool TryUserAuthentication()
        {
            CnrAuthenticationRequiredEventArgs queryArgs = null;
            bool returnValue = false;
            int attemptCount = 0;

            queryArgs = new CnrAuthenticationRequiredEventArgs(_credentials.UserIdentityValue);

            do
            {
                OnUserIdentitySent(new CnrAuthenticationEventArgs());
                returnValue = PerformUserIdentification();
                if (!returnValue)
                {
                    OnUserIdentityRejected(new CnrAuthenticationEventArgs());
                    if (_queryForCredentials)
                    {
                        OnQueryCredentials(queryArgs);
                        if (queryArgs.Cancel)
                            attemptCount = _retryAttempts;
                        else
                        {
                            _credentials.SecurityValue = queryArgs.UserPasswordValue;
                            _credentials.UserIdentityValue = queryArgs.UserIdentityValue;
                        }
                    }
                    attemptCount++;
                }
                else
                    OnUserIdentityAccepted(new CnrAuthenticationEventArgs());

            } while ((!returnValue) && (attemptCount < _retryAttempts));

            return returnValue;
        }
        /// <summary>
        /// Attempts the authenticate the security/password value.
        /// </summary>
        /// <remarks>
        /// This method may attempt to re-try on failure, and query for credentials if the flag is set.
        /// 
        /// The method calls the <see cref="PerformSecurityValidation"/> implementation.
        /// </remarks>
        /// <returns>
        /// <b>true</b> if the operation is successful; otherwise, <b>false</b>.
        /// </returns>
        protected virtual bool TrySecurityValidation()
        {
            CnrAuthenticationRequiredEventArgs queryArgs = null;
            bool returnValue = false;
            int attemptCount = 0;

            queryArgs = new CnrAuthenticationRequiredEventArgs(_credentials.UserIdentityValue);

            do
            {
                OnUserPasswordSent(new CnrAuthenticationEventArgs());
                returnValue = PerformSecurityValidation();
                if (!returnValue)
                {
                    OnUserPasswordRejected(new CnrAuthenticationEventArgs());
                    if (_queryForCredentials)
                    {
                        OnQueryCredentials(queryArgs);
                        if (queryArgs.Cancel)
                            attemptCount = _retryAttempts;
                        else
                        {
                            _credentials.SecurityValue = queryArgs.UserPasswordValue;
                            _credentials.UserIdentityValue = queryArgs.UserIdentityValue;
                        }
                    }
                    attemptCount++;
                }
                else
                    OnUserPasswordAccepted(new CnrAuthenticationEventArgs());

            } while ((!returnValue) && (attemptCount < _retryAttempts));

            return returnValue;
        }
        /// <summary>
        /// Attempts the custom operation.
        /// </summary>
        /// <remarks>
        /// This method may attempt to re-try on failure.
        /// 
        /// The method calls the <see cref="PerformCustomOperation"/> implementation.
        /// </remarks>
        /// <returns>
        /// <b>true</b> if the operation is successful; otherwise, <b>false</b>.
        /// </returns>
        protected virtual bool TryCustomOperation()
        {
            bool returnValue = false;
            int attemptCount = 0;

            do
            {
                returnValue = PerformCustomOperation();
                attemptCount++;

            } while ((!returnValue) && (attemptCount < _retryAttempts));

            return returnValue;
        }

        #endregion

        /*--------------------------------------------------------------------------------
         * Event Methods 
         *------------------------------------------------------------------------------*/
        #region Event Methods
        /// <summary>
        /// Raises the <see cref="UserIdentitySent"/> event.
        /// </summary>
        /// <param name="e">
        /// A <see cref="CnrAuthenticationEventArgs"/> event arguments instance.
        /// </param>
        protected virtual void OnUserIdentitySent(CnrAuthenticationEventArgs e)
        {
            if (UserIdentitySent != null)
                UserIdentitySent(this, e);

        }
        /// <summary>
        /// Raises the <see cref="UserIdentityAccepted"/> event.
        /// </summary>
        /// <param name="e">
        /// A <see cref="CnrAuthenticationEventArgs"/> event arguments instance.
        /// </param>
        protected virtual void OnUserIdentityAccepted(CnrAuthenticationEventArgs e)
        {
            if (UserIdentityAccepted != null)
                UserIdentityAccepted(this, e);

        }
        /// <summary>
        /// Raises the <see cref="UserIdentityRejected"/> event.
        /// </summary>
        /// <param name="e">
        /// A <see cref="CnrAuthenticationEventArgs"/> event arguments instance.
        /// </param>
        protected virtual void OnUserIdentityRejected(CnrAuthenticationEventArgs e)
        {
            if (UserIdentityRejected != null)
                UserIdentityRejected(this, e);

        }
        /// <summary>
        /// Raises the <see cref="UserPasswordSent"/> event.
        /// </summary>
        /// <param name="e">
        /// A <see cref="CnrAuthenticationEventArgs"/> event arguments instance.
        /// </param>
        protected virtual void OnUserPasswordSent(CnrAuthenticationEventArgs e)
        {
            if (UserPasswordSent != null)
                UserPasswordSent(this, e);

        }
        /// <summary>
        /// Raises the <see cref="UserPasswordAccepted"/> event.
        /// </summary>
        /// <param name="e">
        /// A <see cref="CnrAuthenticationEventArgs"/> event arguments instance.
        /// </param>
        protected virtual void OnUserPasswordAccepted(CnrAuthenticationEventArgs e)
        {
            if (UserPasswordAccepted != null)
                UserPasswordAccepted(this, e);

        }
        /// <summary>
        /// Raises the <see cref="UserPasswordRejected"/> event.
        /// </summary>
        /// <param name="e">
        /// A <see cref="CnrAuthenticationEventArgs"/> event arguments instance.
        /// </param>
        protected virtual void OnUserPasswordRejected(CnrAuthenticationEventArgs e)
        {
            if (UserPasswordRejected != null)
                UserPasswordRejected(this, e);

        }
        /// <summary>
        /// Raises the <see cref="QueryCredentials"/> event.
        /// </summary>
        /// <param name="e">
        /// A <see cref="CnrAuthenticationRequiredEventArgs"/> event arguments instance.
        /// </param>
        protected virtual void OnQueryCredentials(CnrAuthenticationRequiredEventArgs e)
        {
            if (QueryCredentials != null)
                QueryCredentials(this, e);
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Methods / Functions
         *------------------------------------------------------------------------------*/
        #region Public Methods / Functions
        /// <summary>
        /// Clears the contents of the object instance without disposing of the instance.
        /// </summary>
        public override void Clear()
        {
            _credentials.Clear();
            _retryAttempts = 0;
            _queryForCredentials = false;
        }
        /// <summary>
        /// Executes the authentication process.
        /// </summary>
        /// <returns>
        /// <b>true</b> if the authentication is successful; otherwise, <b>false</b>.
        /// </returns>
        public virtual bool ExecuteAuthentication()
        {
            bool returnValue = false;

            returnValue = TryUserAuthentication();
            if (returnValue)
            {
                returnValue = TrySecurityValidation();
                if (returnValue)
                {
                    returnValue = TryCustomOperation();
                }
            }
            return returnValue;
        }
        #endregion
    }
}